"""
AI Integration Services
AI功能集成服务层
"""
import json
import logging
import requests
import time
from typing import Dict, List, Optional, Any, Union
from datetime import datetime, timedelta
from django.core.cache import cache
from django.conf import settings
from django.utils import timezone
from rest_framework import status
from .ai_config import (
    AI_API_KEY, AI_API_URL, AI_MODEL, AI_MAX_TOKENS, AI_TEMPERATURE,
    AI_ENABLE_CACHE, AI_CACHE_TTL, AI_REQUESTS_PER_MINUTE, AI_MAX_RETRIES,
    AI_TIMEOUT_SECONDS, AI_SUBJECT_PROMPTS, AI_GRADING_PROMPTS,
    AI_QUESTION_GENERATION_ENABLED, AI_GRADING_ASSISTANT_ENABLED,
    AI_USE_NEW_PROMPT_SYSTEM
)
from .prompts import prompt_manager, PromptType, Subject

logger = logging.getLogger(__name__)

class AIServiceError(Exception):
    """AI服务异常基类"""
    pass

class AIRateLimitError(AIServiceError):
    """AI服务速率限制异常"""
    pass

class AIAPIError(AIServiceError):
    """AI API调用异常"""
    pass

class AIContentModerationError(AIServiceError):
    """AI内容审核异常"""
    pass

class AIService:
    """AI服务主类"""

    def __init__(self):
        self.api_key = AI_API_KEY
        self.api_url = AI_API_URL
        self.model = AI_MODEL
        self.max_tokens = AI_MAX_TOKENS
        self.temperature = AI_TEMPERATURE
        self.session = requests.Session()
        self.session.headers.update({
            'Authorization': f'Bearer {self.api_key}',
            'Content-Type': 'application/json',
            'User-Agent': 'AI-SOES/1.0'
        })

    def _check_rate_limit(self, user_id: str = None) -> bool:
        """检查速率限制"""
        cache_key = f"ai_rate_limit:{user_id or 'anonymous'}"
        current_requests = cache.get(cache_key, 0)

        if current_requests >= AI_REQUESTS_PER_MINUTE:
            raise AIRateLimitError("AI服务请求过于频繁，请稍后再试")

        cache.set(cache_key, current_requests + 1, 60)  # 1分钟过期
        return True

    def _get_cache_key(self, prompt: str, **kwargs) -> str:
        """生成缓存键"""
        import hashlib
        content = f"{prompt}:{json.dumps(kwargs, sort_keys=True)}"
        return f"ai_cache:{hashlib.md5(content.encode()).hexdigest()}"

    def _call_api(self, messages: List[Dict], user_id: str = None, **kwargs) -> Dict:
        """调用AI API"""
        try:
            # 检查速率限制
            self._check_rate_limit(user_id)

            # 检查缓存
            if AI_ENABLE_CACHE:
                cache_key = self._get_cache_key(str(messages), **kwargs)
                cached_result = cache.get(cache_key)
                if cached_result:
                    logger.info(f"AI响应缓存命中: {cache_key}")
                    return cached_result

            # 准备请求数据
            data = {
                "model": self.model,
                "max_tokens": self.max_tokens,
                "temperature": self.temperature,
                "messages": messages
            }

            # 添加额外参数
            data.update(kwargs)

            # 重试机制
            last_exception = None
            for attempt in range(AI_MAX_RETRIES):
                try:
                    logger.info(f"AI API请求尝试 {attempt + 1}/{AI_MAX_RETRIES}")
                    response = self.session.post(
                        self.api_url,
                        json=data,
                        timeout=AI_TIMEOUT_SECONDS
                    )
                    response.raise_for_status()

                    result = response.json()

                    # 缓存结果
                    if AI_ENABLE_CACHE and 'choices' in result:
                        cache.set(cache_key, result, AI_CACHE_TTL)

                    logger.info("AI API调用成功")
                    return result

                except requests.exceptions.Timeout:
                    last_exception = AIAPIError("AI服务响应超时")
                    logger.warning(f"AI API请求超时，尝试 {attempt + 1}/{AI_MAX_RETRIES}")

                except requests.exceptions.RequestException as e:
                    last_exception = AIAPIError(f"AI API请求失败: {str(e)}")
                    logger.warning(f"AI API请求异常，尝试 {attempt + 1}/{AI_MAX_RETRIES}: {str(e)}")

                if attempt < AI_MAX_RETRIES - 1:
                    time.sleep(2 ** attempt)  # 指数退避

            raise last_exception

        except AIRateLimitError:
            raise
        except Exception as e:
            logger.error(f"AI API调用失败: {str(e)}")
            raise AIAPIError(f"AI服务调用失败: {str(e)}")

class QuestionGenerationService(AIService):
    """智能题目生成服务"""

    def generate_question(self, subject: str, topic: str, difficulty: str = 'medium',
                         question_type: str = 'single_choice', count: int = 1,
                         additional_context: str = None, user_id: str = None,
                         grade_level: str = None) -> Dict:
        """生成题目"""

        if not AI_QUESTION_GENERATION_ENABLED:
            raise AIServiceError("AI题目生成功能已禁用")

        try:
            if AI_USE_NEW_PROMPT_SYSTEM:
                # 使用新的提示词管理系统
                return self._generate_question_with_new_system(
                    subject, topic, difficulty, question_type, count,
                    additional_context, user_id, grade_level
                )
            else:
                # 使用旧的提示词系统（向后兼容）
                return self._generate_question_with_legacy_system(
                    subject, topic, difficulty, question_type, count,
                    additional_context, user_id
                )
        except Exception as e:
            logger.error(f"题目生成失败: {str(e)}")
            return {
                'success': False,
                'error': str(e),
                'generated_at': timezone.now().isoformat()
            }

    def _generate_question_with_new_system(self, subject: str, topic: str, difficulty: str,
                                         question_type: str, count: int, additional_context: str,
                                         user_id: str, grade_level: str) -> Dict:
        """使用新提示词系统生成题目"""

        # 确定使用哪个模板
        template_id = self._get_question_template_id(subject, question_type)
        if not template_id:
            raise AIServiceError(f"未找到适合的模板: {subject} - {question_type}")

        # 准备模板变量
        variables = {
            'topic': topic,
            'difficulty': difficulty,
            'question_type': question_type,
            'count': count,
            'grade_level': grade_level or self._infer_grade_level(difficulty)
        }

        # 渲染提示词
        system_prompt = prompt_manager.render_template(template_id, variables)

        # 如果有额外要求，添加到用户消息中
        user_prompt = f"请按照上述要求生成题目。"
        if additional_context:
            user_prompt += f"\n额外要求：{additional_context}"

        messages = [
            {"role": "system", "content": system_prompt},
            {"role": "user", "content": user_prompt}
        ]

        response = self._call_api(messages, user_id)
        content = response.get('choices', [{}])[0].get('message', {}).get('content', '')

        # 使用新的解析方法
        questions = self._parse_generated_questions_enhanced(content, question_type, count)

        return {
            'success': True,
            'questions': questions,
            'subject': subject,
            'topic': topic,
            'difficulty': difficulty,
            'question_type': question_type,
            'template_id': template_id,
            'grade_level': grade_level,
            'generated_at': timezone.now().isoformat(),
            'usage': response.get('usage', {}),
            'prompt_version': '2.0'
        }

    def _generate_question_with_legacy_system(self, subject: str, topic: str, difficulty: str,
                                            question_type: str, count: int, additional_context: str,
                                            user_id: str) -> Dict:
        """使用旧提示词系统生成题目（向后兼容）"""

        # 构建提示词
        prompt = self._build_question_prompt(subject, topic, difficulty, question_type, count, additional_context)

        messages = [
            {"role": "system", "content": AI_SUBJECT_PROMPTS.get(subject, "你是一个专业的题目生成助手。")},
            {"role": "user", "content": prompt}
        ]

        response = self._call_api(messages, user_id)
        content = response.get('choices', [{}])[0].get('message', {}).get('content', '')

        # 结构化处理生成的题目
        questions = self._parse_generated_questions(content, question_type, count)

        return {
            'success': True,
            'questions': questions,
            'subject': subject,
            'topic': topic,
            'difficulty': difficulty,
            'question_type': question_type,
            'generated_at': timezone.now().isoformat(),
            'usage': response.get('usage', {}),
            'prompt_version': '1.0'
        }

    def _get_question_template_id(self, subject: str, question_type: str) -> Optional[str]:
        """获取对应的模板ID"""
        template_mapping = {
            ('math', 'single_choice'): 'math_question_generation',
            ('math', 'multiple_choice'): 'math_question_generation',
            ('chinese', 'reading_comprehension'): 'chinese_reading_comprehension',
            ('english', 'grammar'): 'english_grammar_question',
            ('english', 'single_choice'): 'english_grammar_question',
            ('english', 'multiple_choice'): 'english_grammar_question',
        }
        return template_mapping.get((subject, question_type), 'math_question_generation')

    def _infer_grade_level(self, difficulty: str) -> str:
        """根据难度推断年级"""
        grade_mapping = {
            'easy': '小学',
            'medium': '初中',
            'hard': '高中',
            'advanced': '高中或大学'
        }
        return grade_mapping.get(difficulty, '初中')

    def _parse_generated_questions_enhanced(self, content: str, question_type: str, expected_count: int) -> List[Dict]:
        """增强的题目解析方法"""
        try:
            # 尝试直接解析JSON
            if content.strip().startswith('{'):
                data = json.loads(content)
                if 'questions' in data:
                    return data['questions']
                elif 'reading_material' in data and 'questions' in data:
                    # 阅读理解题的特殊处理
                    return data['questions']

            # 尝试提取JSON部分
            import re
            json_patterns = [
                r'\{[^{}]*"questions"[^{}]*\}',  # 简单JSON
                r'\{(?:[^{}]|(?R))*"questions"(?:[^{}]|(?R))*\}',  # 嵌套JSON
            ]

            for pattern in json_patterns:
                json_match = re.search(pattern, content, re.DOTALL)
                if json_match:
                    try:
                        data = json.loads(json_match.group())
                        if 'questions' in data:
                            return data['questions']
                    except:
                        continue

            # 如果无法解析，创建基础结构
            return self._create_fallback_questions(content, question_type, expected_count)

        except Exception as e:
            logger.warning(f"解析生成的题目失败: {str(e)}")
            return self._create_fallback_questions(content, question_type, expected_count)

    def _create_fallback_questions(self, content: str, question_type: str, count: int) -> List[Dict]:
        """创建后备题目结构"""
        questions = []
        for i in range(count):
            questions.append({
                'title': f'生成的{question_type}题目 {i+1}',
                'content': content.strip() if i == 0 else f'题目 {i+1}',
                'options': [] if question_type in ['short_answer', 'essay'] else ['A', 'B', 'C', 'D'],
                'correct_answer': 'A' if question_type in ['single_choice', 'true_false'] else '',
                'explanation': 'AI生成题目的解析',
                'difficulty': 'medium',
                'topic': '通用',
                'estimated_time': 300,
                'score': 10,
                'solution_steps': [],
                'key_points': []
            })
        return questions

    def _build_question_prompt(self, subject: str, topic: str, difficulty: str,
                              question_type: str, count: int, additional_context: str = None) -> str:
        """构建题目生成提示词"""

        difficulty_levels = {
            'easy': '简单/基础',
            'medium': '中等/一般',
            'hard': '困难/高级'
        }

        type_descriptions = {
            'single_choice': '单选题',
            'multiple_choice': '多选题',
            'true_false': '判断题',
            'short_answer': '简答题',
            'essay': '论述题/作文',
            'fill_blank': '填空题'
        }

        prompt = f"""
请为{subject}学科生成{count}道{type_descriptions.get(question_type, '题目')}。

要求：
1. 知识点：{topic}
2. 难度级别：{difficulty_levels.get(difficulty, '中等')}
3. 题目类型：{type_descriptions.get(question_type)}
4. 题目数量：{count}

请按以下JSON格式返回题目：
{{
    "questions": [
        {{
            "title": "题目标题",
            "content": "题目内容",
            "options": ["选项A", "选项B", "选项C", "选项D"],
            "correct_answer": "正确答案",
            "explanation": "答案解析",
            "difficulty": "{difficulty}",
            "topic": "{topic}",
            "estimated_time": 300,
            "score": 10
        }}
    ]
}}
"""

        if additional_context:
            prompt += f"\n额外要求：{additional_context}"

        return prompt

    def _parse_generated_questions(self, content: str, question_type: str, expected_count: int) -> List[Dict]:
        """解析生成的题目"""
        try:
            # 尝试直接解析JSON
            if content.strip().startswith('{'):
                data = json.loads(content)
                return data.get('questions', [])

            # 尝试提取JSON部分
            import re
            json_match = re.search(r'\{.*\}', content, re.DOTALL)
            if json_match:
                data = json.loads(json_match.group())
                return data.get('questions', [])

            # 如果无法解析JSON，创建基础结构
            return [{
                'title': f'生成的{question_type}题目',
                'content': content.strip(),
                'options': [] if question_type in ['short_answer', 'essay'] else ['A', 'B', 'C', 'D'],
                'correct_answer': 'A',
                'explanation': 'AI生成题目的解析',
                'difficulty': 'medium',
                'topic': '通用',
                'estimated_time': 300,
                'score': 10
            }]

        except Exception as e:
            logger.warning(f"解析生成的题目失败: {str(e)}")
            return [{
                'title': 'AI生成题目',
                'content': content.strip(),
                'options': [],
                'correct_answer': '',
                'explanation': 'AI生成的题目内容',
                'difficulty': 'medium',
                'topic': '通用',
                'estimated_time': 300,
                'score': 10
            }]

class GradingAssistantService(AIService):
    """AI评分助手服务"""

    def grade_essay(self, essay_content: str, essay_prompt: str,
                   rubric: str = None, max_score: int = 100, user_id: str = None) -> Dict:
        """作文评分"""

        if not AI_GRADING_ASSISTANT_ENABLED:
            raise AIServiceError("AI评分助手功能已禁用")

        prompt = self._build_grading_prompt(essay_content, essay_prompt, rubric, max_score, 'essay')

        messages = [
            {"role": "system", "content": AI_GRADING_PROMPTS['essay']},
            {"role": "user", "content": prompt}
        ]

        try:
            response = self._call_api(messages, user_id)
            content = response.get('choices', [{}])[0].get('message', {}).get('content', '')

            # 解析评分结果
            grading_result = self._parse_grading_result(content, 'essay')

            return {
                'success': True,
                'grading': grading_result,
                'max_score': max_score,
                'graded_at': timezone.now().isoformat(),
                'usage': response.get('usage', {})
            }

        except Exception as e:
            logger.error(f"作文评分失败: {str(e)}")
            return {
                'success': False,
                'error': str(e),
                'graded_at': timezone.now().isoformat()
            }

    def grade_short_answer(self, student_answer: str, reference_answer: str,
                          question: str = None, max_score: int = 10, user_id: str = None) -> Dict:
        """简答题评分"""

        if not AI_GRADING_ASSISTANT_ENABLED:
            raise AIServiceError("AI评分助手功能已禁用")

        prompt = self._build_grading_prompt(student_answer, reference_answer, question, max_score, 'short_answer')

        messages = [
            {"role": "system", "content": AI_GRADING_PROMPTS['short_answer']},
            {"role": "user", "content": prompt}
        ]

        try:
            response = self._call_api(messages, user_id)
            content = response.get('choices', [{}])[0].get('message', {}).get('content', '')

            # 解析评分结果
            grading_result = self._parse_grading_result(content, 'short_answer')

            return {
                'success': True,
                'grading': grading_result,
                'max_score': max_score,
                'graded_at': timezone.now().isoformat(),
                'usage': response.get('usage', {})
            }

        except Exception as e:
            logger.error(f"简答题评分失败: {str(e)}")
            return {
                'success': False,
                'error': str(e),
                'graded_at': timezone.now().isoformat()
            }

    def _build_grading_prompt(self, student_answer: str, reference: str,
                             rubric: str, max_score: int, grading_type: str) -> str:
        """构建评分提示词"""

        if grading_type == 'essay':
            prompt = f"""
请对以下作文进行评分：

作文题目：{reference}
学生作文：
{student_answer}

评分标准：满分{max_score}分
"""
            if rubric:
                prompt += f"\n具体要求：{rubric}"

        else:  # short_answer
            prompt = f"""
请对以下简答题进行评分：

题目：{reference if not rubric else rubric}
标准答案：{reference}
学生回答：{student_answer}

满分：{max_score}分
"""

        prompt += """
请按以下格式返回评分结果：
{
    "score": 得分,
    "score_percentage": 得分百分比,
    "strengths": ["优点1", "优点2"],
    "weaknesses": ["不足1", "不足2"],
    "detailed_feedback": "详细评语",
    "suggestions": ["改进建议1", "改进建议2"]
}
"""
        return prompt

    def _parse_grading_result(self, content: str, grading_type: str) -> Dict:
        """解析评分结果"""
        try:
            # 尝试直接解析JSON
            if content.strip().startswith('{'):
                return json.loads(content)

            # 尝试提取JSON部分
            import re
            json_match = re.search(r'\{.*\}', content, re.DOTALL)
            if json_match:
                return json.loads(json_match.group())

            # 如果无法解析，返回基础结构
            return {
                'score': 0,
                'score_percentage': 0,
                'strengths': [],
                'weaknesses': [],
                'detailed_feedback': content.strip(),
                'suggestions': []
            }

        except Exception as e:
            logger.warning(f"解析评分结果失败: {str(e)}")
            return {
                'score': 0,
                'score_percentage': 0,
                'strengths': [],
                'weaknesses': [],
                'detailed_feedback': content.strip(),
                'suggestions': []
            }

class AnalyticsService(AIService):
    """AI分析服务"""

    def analyze_learning_progress(self, user_id: str, performance_data: List[Dict]) -> Dict:
        """分析学习进度"""
        prompt = self._build_analytics_prompt('learning_progress', performance_data)

        messages = [
            {"role": "system", "content": "你是一个专业的学习分析助手，请分析学生的学习数据并提供洞察。"},
            {"role": "user", "content": prompt}
        ]

        try:
            response = self._call_api(messages, user_id)
            content = response.get('choices', [{}])[0].get('message', {}).get('content', '')

            return {
                'success': True,
                'analysis': content,
                'analyzed_at': timezone.now().isoformat(),
                'usage': response.get('usage', {})
            }

        except Exception as e:
            logger.error(f"学习进度分析失败: {str(e)}")
            return {
                'success': False,
                'error': str(e),
                'analyzed_at': timezone.now().isoformat()
            }

    def generate_study_recommendations(self, user_id: str, subject: str,
                                     weak_areas: List[str], performance_data: List[Dict]) -> Dict:
        """生成学习建议"""
        prompt = self._build_analytics_prompt('study_recommendations', {
            'subject': subject,
            'weak_areas': weak_areas,
            'performance_data': performance_data
        })

        messages = [
            {"role": "system", "content": "你是一个专业的学习顾问，请根据学生的学习情况提供个性化的学习建议。"},
            {"role": "user", "content": prompt}
        ]

        try:
            response = self._call_api(messages, user_id)
            content = response.get('choices', [{}])[0].get('message', {}).get('content', '')

            return {
                'success': True,
                'recommendations': content,
                'subject': subject,
                'weak_areas': weak_areas,
                'generated_at': timezone.now().isoformat(),
                'usage': response.get('usage', {})
            }

        except Exception as e:
            logger.error(f"学习建议生成失败: {str(e)}")
            return {
                'success': False,
                'error': str(e),
                'generated_at': timezone.now().isoformat()
            }

    def _build_analytics_prompt(self, analysis_type: str, data: Union[Dict, List]) -> str:
        """构建分析提示词"""

        if analysis_type == 'learning_progress':
            return f"""
请分析以下学生的学习数据，提供详细的学习进度分析：

学生表现数据：
{json.dumps(data, indent=2, ensure_ascii=False)}

请提供：
1. 学习趋势分析
2. 强项和弱项识别
3. 知识掌握程度评估
4. 改进建议
"""

        elif analysis_type == 'study_recommendations':
            subject = data.get('subject', '通用')
            weak_areas = data.get('weak_areas', [])
            performance_data = data.get('performance_data', [])

            return f"""
请为学生在{subject}学科的学习提供个性化建议：

薄弱知识点：{', '.join(weak_areas)}
历史表现数据：
{json.dumps(performance_data, indent=2, ensure_ascii=False)}

请提供：
1. 针对薄弱知识点的学习策略
2. 学习资源推荐
3. 练习题建议
4. 学习时间安排建议
"""

        return "请分析提供的数据并提供有价值的见解。"

# 创建服务实例
question_service = QuestionGenerationService()
grading_service = GradingAssistantService()
analytics_service = AnalyticsService()